package com.woniuxy.portal.model.vo;

import lombok.Data;

import java.math.BigDecimal;
import java.util.*;

/**
 * 购物车对象
 */
@Data
public class CartVo {
    //购物项集合(键是书籍ID，值是购物项对象)
    private Map<Long, CartItemVo> items = new LinkedHashMap<>();
    private BigDecimal totalPrice = BigDecimal.ZERO; //总价格
    private Integer amount;        //总数量
    private Long userId;           //用户的id

    /**
     * 添加购物项到购物车中
     * 如果购物车中已存在相同商品，则将数量累加；否则直接添加新的购物项
     * 添加完成后会自动更新购物车的总数量和总价格
     *
     * @param cartItem 要添加的购物项信息，包含商品ID和数量等信息
     */
    public void addItem(CartItemVo cartItem) {
        //判断购物车中是否已经存在该商品
        Long bookId = cartItem.getBookId();
        if (items.containsKey(bookId)) {
            //存在，则更新数量
            CartItemVo item = items.get(bookId);
            item.setQuantity(cartItem.getQuantity() + item.getQuantity());
        } else {
            //不存在，则添加
            items.put(bookId, cartItem);
        }
        //更新总价格和总数量
        updateAmountAndTotalPrice();
    }

    /**
     * 更新总价格和总数量
     * <p>
     * 该方法遍历购物车中的所有商品项，重新计算购物车的总价格和总数量。
     * 总价格通过累加每个商品项的小计金额得到，总数量通过累加每个商品项的数量得到。
     */
    private void updateAmountAndTotalPrice() {
        Collection<CartItemVo> cartItems = items.values();

        // 重新初始化
        this.totalPrice = BigDecimal.ZERO;

        // 累加计算总价格
        cartItems.forEach(item -> {
            // 使用BigDecimal的add方法累加计算后，会返回一个新的BigDecimal对象，
            // 因此需要重新赋值给totalPrice
            BigDecimal sum = item.getSum();
            this.totalPrice = this.totalPrice.add(sum);
        });

        //计算总价格
//        this.totalPrice = cartItems.stream().mapToDouble(item -> item.getSum()).sum();
        //计算总数量
//        this.amount = cartItems.stream().mapToInt(item -> item.getQuantity()).sum();
        this.amount = cartItems.stream().mapToInt(CartItemVo::getQuantity).sum();
    }

    /**
     * 删除购物项
     *
     * @param bookId 要删除的图书ID
     */
    public void removeItem(Long bookId) {
        // 从购物项集合中移除指定图书ID的项
        items.remove(bookId);
        // 更新购物车总金额和总价
        updateAmountAndTotalPrice();
    }

    /**
     * 修改购物项中某件商品的数量
     *
     * @param bookId   商品ID
     * @param quantity 要修改的商品数量
     */
    public void updateItemQuantity(Long bookId, Integer quantity) {
        //判断这件商品是否存在
        if (items.containsKey(bookId)) {
            CartItemVo cartItem = items.get(bookId);
            //判断修改后的数量是否小于等于0
            if (quantity <= 0) {
                //小于等于0，则删除该商品项
                items.remove(bookId);
            } else {
                //大于0，则更新商品数量
                cartItem.setQuantity(quantity);
            }
            //更新购物车总价格和总数量
            updateAmountAndTotalPrice();
        }
    }

    /**
     * 获取购物车中的所有商品
     *
     * @return List<CartItemVo> 购物车中所有商品的列表副本，返回类型为CartItemVo对象的List集合
     */
    public List<CartItemVo> getItemList() {
        return new ArrayList<>(items.values());
    }

    /**
     * 清空购物车
     * 该方法用于清空购物车中的所有商品项，并重新计算购物车的总金额和总价
     */
    public void clearCart() {
        // 清空购物车中的所有商品项
        items.clear();
        // 更新购物车总金额和总价
        updateAmountAndTotalPrice();
    }

    /**
     * 设置购物车商品列表，将列表转换为Map结构以便快速查找
     * Jackson 可以正常反序列化 itemList 了。
     *
     * @param itemList 购物车商品列表
     */
    public void setItemList(List<CartItemVo> itemList) {
        // 为了兼容反序列化，不需要深拷贝也没关系
        this.items = new LinkedHashMap<>();
        // 将列表转换为以bookId为key的Map结构
        for (CartItemVo item : itemList) {
            this.items.put(item.getBookId(), item);
        }
    }

}
